package bjut.core.netty;

import bjut.core.constant.RpcConstant;
import bjut.core.factory.SingletonFactory;
import bjut.core.config.ProviderConfig;
import bjut.core.config.ShutDownHook;
import bjut.core.interfaces.ServiceProvider;
import bjut.core.utils.ThreadPoolUtil;
import bjut.core.zookeeper.ZkServiceProviderImpl;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.DefaultEventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.net.InetAddress;

/**
 * @Author: zhuzhiming
 * @Date: 2022/4/14 20:38
 */
@Component
@Slf4j
public class ZRpcNettyServer {

    public static final int PORT = 2828;

    private final ServiceProvider serviceProvider = SingletonFactory.getInstance(ZkServiceProviderImpl.class);

    public void registerService(ProviderConfig providerConfig) {
        serviceProvider.registerService(providerConfig);
    }

    @SneakyThrows
    public void start() {

        ShutDownHook.clearAll();

        NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        DefaultEventLoopGroup defaultEventLoopGroup = new DefaultEventLoopGroup(Runtime.getRuntime().availableProcessors() * 2, ThreadPoolUtil.createThreadFactory("zRpc", true));

        ServerBootstrap serverBootstrap = new ServerBootstrap();

        try {
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    // TCP默认开启了 Nagle 算法，该算法的作用是尽可能的发送大数据快，减少网络传输。TCP_NODELAY 参数的作用就是控制是否启用 Nagle 算法。
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    // 是否开启 TCP 底层心跳机制
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    //表示系统用于临时存放已完成三次握手的请求的队列的最大长度,如果连接建立频繁，服务器处理创建新连接较慢，可以适当调大这个参数
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new NettyServerChannelInitializer(defaultEventLoopGroup));

            ChannelFuture channelFuture = serverBootstrap.bind(RpcConstant.HOST_ADDRESS, PORT).sync();
            channelFuture.channel().closeFuture().sync();

        } catch (Exception e) {
            log.warn("remote client closed");
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
            defaultEventLoopGroup.shutdownGracefully();
        }

    }

}
